cmake_minimum_required(VERSION 3.7)

# CC CXX CFLAGS CXXFLAGS LDFLAGS
SET(PLATFORM STM32)
SET(CMAKE_SYSTEM_NAME Generic)
#set(CMAKE_CROSSCOMPILING "TRUE")
SET(CMAKE_C_COMPILER "arm-none-eabi-gcc")
SET(CMAKE_CXX_COMPILER "arm-none-eabi-g++")
SET(CMAKE_ASM_COMPILER "arm-none-eabi-gcc")
#set(CMAKE_C_FLAGS -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections)
set(CMAKE_OBJCOPY "arm-none-eabi-objcopy")
set(CMAKE_SIZE "arm-none-eabi-size")
set(CMAKE_ASM_FLAGS " -x assembler-with-cpp")
enable_language(ASM)

add_compile_options(-g -O3 -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections -nostdlib )
add_compile_options(-DUSE_HAL_DRIVER)	
#add_compile_options(-DSTM32F103xE)
add_compile_options(-DSTM32)




#--------------------- generic settings ----------------------

file(RELATIVE_PATH PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR}/.. ${CMAKE_CURRENT_LIST_DIR})
#set(PROJECT_NAME "proj")

set(SRC_EXTS *.cpp *.c *.s)

set(HEADER_EXTS *.h *.hpp)

list(APPEND EXCLUDES ".*/config/.*")

set(FLAGS "")


#----------------------- external config ----------------------
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/config_local.cmake")	
	set(CONFIG_F "${CMAKE_CURRENT_LIST_DIR}/config_local.cmake")	
else()
	set(CONFIG_F "${CMAKE_CURRENT_LIST_DIR}/config.cmake")	
endif()
include("${CONFIG_F}" OPTIONAL)



#----------------------- ld scirpt ----------------------
if(NOT DEFINED LD_SRCS)
	file(GLOB_RECURSE LD_SRCS "*.ld")
endif()
foreach(FNAME IN LISTS LD_SRCS)
	set(LDSCRIPT ${FNAME})
endforeach()
set(LDFLAGS "${LDFLAGS} --specs=nosys.specs -T${LDSCRIPT} -lc_nano -lm -lnosys -mcpu=cortex-m3 -mthumb -Wl,-Map=${PROJNAME}.map,--cref -Wl,--gc-sections")

if(NOT DEFINED ASM_SRCS)
file(GLOB_RECURSE ASM_SRCS "*.s")
endif()



if(DEFINED ENTRY_ADDRESS)
add_compile_options(-DPARTITION_APP=${ENTRY_ADDRESS})
else()
set(ENTRY_ADDRESS 0x08000000)
endif()

#-------------------- default variable --------------------
if(NOT DEFINED NO_CONSOLE)
	set(NO_CONSOLE 0)
endif()
if(NOT DEFINED MAIN_FILTER)
	set(MAIN_FILTER "^main\..*")
endif()
if(NOT DEFINED TEST_FILTER)
	set(TEST_FILTER ".*test.*\..*")
endif()
if(NOT DEFINED BUILD_TEST)
	if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
		set(BUILD_TEST 0)
	else()
		set(BUILD_TEST 0)
	endif()
endif()
set(CFLAGS ${FLAGS})
set(CXXFLAGS ${FLAGS})
#-------------------- generic flags --------------------

set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} ${CFLAGS})
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${CXXFLAGS})
set(CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} ${LDFLAGS})
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} ${LDFLAGS})

set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
project(${PROJECT_NAME})

	
#----------------- no dep libstdc++.so libgcc_s.so -------------------------
set(LDFLAGS "-static ${LDFLAGS}")



#-------------------- touch revision file --------------------
file(MAKE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include")
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/revision.h") 
file(WRITE "${CMAKE_CURRENT_LIST_DIR}/include/revision.h" //)
endif()

#-------------------- glob all files --------------------
file(GLOB_RECURSE ALL_SRCS ${SRC_EXTS})
file(GLOB_RECURSE ALL_HEADERS ${HEADER_EXTS})
file(GLOB_RECURSE SUB_CMAKES */CMakeLists.txt)



#-------------------- deps libs --------------------
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
foreach(DEP IN LISTS LIBS)
if(EXISTS ${CMAKE_MODULE_PATH}/Find${DEP}.cmake)
	find_package(${DEP})
endif()
endforeach()


#-------------------- exclude files --------------------
list(FILTER ALL_SRCS EXCLUDE REGEX "CMakeFiles")
list(FILTER ALL_HEADERS EXCLUDE REGEX "CMakeFiles")
foreach(EXCL IN LISTS EXCLUDES) 
	#message("excl ${EXCL}")
	list(FILTER ALL_SRCS EXCLUDE REGEX ${EXCL})
	list(FILTER ALL_HEADERS EXCLUDE REGEX ${EXCL})
endforeach()

#-------------------- src types --------------------
set(HAS_TEST 0)
set(HAS_LIB 0)
set(HAS_MAIN 0)
foreach(SRC IN LISTS ALL_SRCS)
	get_filename_component(FILENAME ${SRC} NAME)	
	if(${FILENAME} MATCHES ${TEST_FILTER})
		list(APPEND TEST_SRCS ${SRC})
		set(HAS_TEST 1)
		#message("test:"  ${SRC})	
	elseif(${FILENAME} MATCHES ${MAIN_FILTER})
		list(APPEND MAIN_SRCS ${SRC})
		set(HAS_MAIN 1)
		#message("main:"  ${SRC})
	else()
		list(APPEND LIB_SRCS ${SRC})
		set(HAS_LIB 1)
		#message("lib :"  ${SRC})	
	endif()
endforeach()

#-------------------- includes --------------------
foreach(FILENAME IN LISTS ALL_HEADERS)
	get_filename_component(DIRNAME ${FILENAME} DIRECTORY)	
	if(NOT "${DIRNAME}" IN_LIST INCS)
		list(APPEND INCS ${DIRNAME})		
	endif()
endforeach()
foreach(INC IN LISTS INCS)
	include_directories(${INC})
endforeach()

#---------------- defines --------------
foreach(DEF IN LISTS DEFINES)
	add_definitions(-D${DEF})
endforeach()


#-- default build
set(PROJNAME ${PROJECT_NAME}) 
add_executable(${PROJNAME}.elf ${MAIN_SRCS} ${LIB_SRCS} ${ASM_SRCS} )
set_target_properties(${PROJNAME}.elf PROPERTIES LINK_DEPENDS ${LDSCRIPT})
add_custom_command(TARGET ${PROJNAME}.elf  POST_BUILD COMMAND ${CMAKE_SIZE} ${PROJNAME}.elf )

include(packages.cmake OPTIONAL)

add_custom_command(OUTPUT ${PROJNAME}.bin DEPENDS ${PROJNAME}.elf COMMAND ${CMAKE_OBJCOPY} -Obinary ${PROJNAME}.elf ${PROJNAME}.bin)
add_custom_target(exportbin ALL DEPENDS ${PROJNAME}.bin)


# ------------- flash command -------------

set(JLINKCMD "")
set(JLINKCMD "${JLINKCMD}h\r\n")
set(JLINKCMD "${JLINKCMD}loadfile ${CMAKE_BINARY_DIR}/${PROJNAME}.bin ${ENTRY_ADDRESS}\r\n")
set(JLINKCMD "${JLINKCMD}g\r\n")
set(JLINKCMD "${JLINKCMD}r\r\n")
set(JLINKCMD "${JLINKCMD}q\r\n")
file(WRITE ${CMAKE_BINARY_DIR}/jlink.txt ${JLINKCMD})

add_custom_target(flash DEPENDS ${PROJNAME}.elf COMMAND JLink -device ${MCU_NAME} -if SWD -speed auto -CommanderScript ${CMAKE_BINARY_DIR}/jlink.txt)


# ------------- gdb server command -------------

set(GDB_SERVER_CMD "JLinkGDBServerCL -nogui -singlerun -select USB -device ${MCU_NAME} -endian little -if SWD -speed auto -noir -LocalhostOnly")

add_custom_target(gdb_server DEPENDS ${PROJNAME}.elf COMMAND ${GDB_SERVER_CMD})

file(WRITE ${CMAKE_BINARY_DIR}/gdb_server.bat "start /MIN ${GDB_SERVER_CMD}")


